﻿/*
 * Copyright (c) 2009, Thiago M. Sayao <thiago.sayao@gmail.com>
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without 
 * modification, are permitted provided that the following conditions are met:
 *  * Redistributions of source code must retain the above copyright notice, 
 *    this list of conditions and the following disclaimer.
 *  * Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *  * Neither the name of the author nor the names of its contributors may be 
 *    used to endorse or promote products derived from this software without 
 *    specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
 * POSSIBILITY OF SUCH DAMAGE.
 */

using System;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Html;
using System.Web.Caching;
using System.Web.Routing;
using System.Collections.Generic;
using System.Text;
using DotNetBurner.Model;
using DotNetBurner.Core;
using DotNetBurner.Web;
using DotNetBurner.Web.Settings;
using System.Globalization;
using Resources;

namespace DotNetBurner
{
    public static class HtmlHelperExtensionsWithCache
    {

        public static string Menu(this HtmlHelper helper, IEnumerable<Category> categories)
        {
            string key = "category-menu";
            string html;

            if (Cache.TryGet(key, out html))
                return html;

            UrlHelper urlHelper = new UrlHelper(helper.ViewContext.RequestContext);

            StringBuilder str = new StringBuilder();

            foreach (Category category in categories)
            {
                str.Append("<li class=\"drop-menu\">");

                var action = urlHelper.Action("Category", "Story",
                                              new RouteValueDictionary
                                                  {
                                                      {"id", category.CategoryId},
                                                      {"name", category.Name.ConvertToUrlPath()},
                                                      {"sort", SwissKnife.GetSortString(0)},
                                                      {"page", 1}
                                                  });

                str.AppendFormat ("<a href=\"{0}\" class=\"drop-menu-link\">{1}</a>", action, category.Name.HtmlEncode ());
                str.Append("<ul class=\"drop-submenu\">");
                foreach (Category subCategory in category.SubCategories)
                {
                    action = urlHelper.Action("Category", "Story",
                                              new RouteValueDictionary
                                              {
                                                  {"id", subCategory.CategoryId},
                                                  {"name", subCategory.Name.ConvertToUrlPath()},
                                                  {"sort", SwissKnife.GetSortString(0)},
                                                  {"page", 1}
                                              });

                    str.Append("<li>");
                    str.AppendFormat("<a href=\"{0}\">{1}</a>", action, subCategory.Name.HtmlEncode());
                    str.Append("</li>");
                }
                str.Append("</ul>");
                str.Append("</li>");
            }

            html = str.ToString();

            Cache.CacheData(key, "Html", html);

            return html;
        }

        public static string SortFilters(this HtmlHelper helper, string action, string name, int sdays)
        {
            string key = "sort-filters-html-{0}-{1}-{2}".FormatWith(action, name, sdays);
            string html;

            if (HttpRuntime.Cache.TryGet(key, out html))
                return html;

            StringBuilder b = new StringBuilder();

            b.Append(helper.ActionLink(Strings.Latest, action, new { @page = 1, sort = "latest", name }, new { @class = (sdays == 0) ? "selected" : "" }));
            b.Append(helper.ActionLink(Strings.Top24Hours, action, new { @page = 1, sort = "24hours", name }, new { @class = (sdays == 1) ? "selected" : "" }));
            b.Append(helper.ActionLink(Strings.OneWeek, action, new { @page = 1, sort = "7days", name }, new { @class = (sdays == 7) ? "selected" : "" }));
            b.Append(helper.ActionLink(Strings.OneMonth, action, new { @page = 1, sort = "1month", name }, new { @class = (sdays == 30) ? "selected" : "" }));
            b.Append(helper.ActionLink(Strings.OneYear, action, new { @page = 1, sort = "1year", name }, new { @class = (sdays == 365) ? "selected" : "" }));

            html = b.ToString();

            Cache.CacheData(key, "Html", html);

            return html;
        }

        public static string SyndicationLinks(this HtmlHelper helper, string feedRoute, int sdays)
        {
            string key = "synd-links-html-{0}-{1}".FormatWith(feedRoute, sdays);
            string html;

            if (Cache.TryGet(key, out html))
                return html;

            UrlHelper urlHelper = new UrlHelper(helper.ViewContext.RequestContext);

            string rss  = urlHelper.RouteUrl(feedRoute, new RouteValueDictionary {{"feedType", "rss"}, {"sort", SwissKnife.GetSortString(sdays)}});
            string atom = urlHelper.RouteUrl(feedRoute, new RouteValueDictionary {{"feedType", "atom"}, {"sort", SwissKnife.GetSortString(sdays)}});

            //find substitutes (eg: feedburner)
            rss  = FeedSettings.GetFeedSubstitute(rss);
            atom = FeedSettings.GetFeedSubstitute(atom);

            StringBuilder str = new StringBuilder();

            string fmt = "<a href=\"{0}\" title=\"{1}\"><span class=\"{2}\"></span></a>";

            str.Append(fmt.FormatWith(rss.AttributeEncode(), Strings.RSSFeedTitle, "feed-rss"));
            str.Append("&nbsp;");
            str.Append(fmt.FormatWith(atom.AttributeEncode(), Strings.AtomFeedTitle, "feed-atom"));

            html = str.ToString();

            Cache.CacheData(key, "Html", html);

            return html;
        }

        public static string HeaderSyndicationLinks(this HtmlHelper helper)
        {
            string key = "header-synd";
            string html;

            if (Cache.TryGet(key, out html))
                return html;

            //RouteCollection is used here so we don't use the current one, which may have some parameters 
            //that would screw the URL
            UrlHelper urlHelper = new UrlHelper(helper.ViewContext.RequestContext);

            string rss  = urlHelper.RouteUrl("IndexFeed", new RouteValueDictionary {{"feedType", "rss"}, {"sort", SwissKnife.GetSortString(0)}});
            string atom = urlHelper.RouteUrl("IndexFeed", new RouteValueDictionary {{"feedType", "atom"}, {"sort", SwissKnife.GetSortString(0)}});

            //find substitutes (eg: feedburner)
            rss  = FeedSettings.GetFeedSubstitute(rss);
            atom = FeedSettings.GetFeedSubstitute(atom);

            string format = "<link rel=\"alternate\" type=\"application/{0}+xml\" title=\"{1} {2} Feeds\" href=\"{3}\" />";

            StringBuilder ret = new StringBuilder();

            ret.Append(format.FormatWith("rss", SiteSettings.Settings.Name, "RSS", rss.AttributeEncode()));
            ret.Append(format.FormatWith("atom", SiteSettings.Settings.Name, "ATOM", atom.AttributeEncode()));

            html = ret.ToString();

            Cache.CacheData(key, "Html", html);

            return html;
        }

        public static string TagCloud(this HtmlHelper helper, IEnumerable<Tag> tags)
        {
            string key = "tag-cloud";
            string html;

            if (Cache.TryGet(key, out html))
                return html;

            if (tags.Count() == 0)
                return String.Empty;

            int minWeight = int.MaxValue;
            int maxWeight = int.MinValue;

            foreach (var tag in tags)
            {
                if (tag.StoryCount < minWeight)
                {
                    minWeight = tag.StoryCount;
                }

                if (tag.StoryCount > maxWeight)
                {
                    maxWeight = tag.StoryCount;
                }
            }

            var styles = new[] { "tag-1", "tag-2", "tag-3", "tag-4", "tag-5", "tag-6", "tag-7" };
            var scaleUnitLength = Convert.ToDecimal(maxWeight - minWeight + 1) / Convert.ToDecimal(styles.Length);

            var tagCloudHtml = new StringBuilder();

            foreach (var tagItem in tags)
            {
                var styleIndex = Convert.ToInt32(Math.Truncate(Convert.ToDecimal(tagItem.StoryCount - minWeight) / scaleUnitLength));
                var encodedTag = tagItem.Name.ConvertToUrlPath();

                //RouteValueDicionary and Dictionary<string, object> are used here for performance gain
                var link = helper.RouteLink(tagItem.Name, "Tag",
                                            new RouteValueDictionary
                                                {
                                                    {"id", tagItem.TagId}, 
                                                    {"name", encodedTag}, 
                                                    {"page", 1},
                                                    {"sort", SwissKnife.GetSortString(0)}
                                                },
                                            new Dictionary<string, object>
                                                {
                                                    {"class", styles[styleIndex]}
                                                });

                tagCloudHtml.AppendFormat("{0} ", link);
            }

            html = tagCloudHtml.ToString();

            Cache.CacheData(key, "Html", html);

            return html;
        }

        public static string TopUsers(this HtmlHelper helper, string key, IEnumerable<TopUser> topUsers)
        {
            string html;

            if (Cache.TryGet(key, out html))
                return html;

            var topUsersHtml = new StringBuilder();

            topUsersHtml.Append("<table cellpadding=\"2\" cellspacing=\"0\" border=\"0\">");
            topUsersHtml.Append("<tbody>");

            int count = 0;
            foreach (var user in topUsers)
            {
                string klass = (count % 2 == 0) ? "even" : "odd";

                topUsersHtml.AppendFormat("<tr class=\"{0}\">", klass);
                topUsersHtml.AppendFormat("<td class=\"rank\">{0}</td>", helper.GetVoteImages(count + 1));


                topUsersHtml.AppendFormat("<td>{0}</td>", helper.Gravatar(user.Email, 24));
                topUsersHtml.Append("<td>");
                var link = helper.RouteLink(user.Name, "PostedBy", new RouteValueDictionary
                                                                       {
                                                                           {"id", user.UserId}, 
                                                                           {"name", user.Name.ConvertToUrlPath()}
                                                                       });
                topUsersHtml.Append(link);
                topUsersHtml.Append("</td>");
                topUsersHtml.Append("<td>");
                topUsersHtml.AppendFormat("{0}<br />", user.Points.ToString("N", CultureInfo.CreateSpecificCulture(SiteSettings.Settings.Language)));
                topUsersHtml.AppendFormat("<span class=\"points\">{0}</span>", Strings.Points);
                topUsersHtml.Append("</td>");
                topUsersHtml.Append("</tr>");

                count++;
            }

            topUsersHtml.Append("</tbody>");
            topUsersHtml.Append("</table>");

            html = topUsersHtml.ToString();

            Cache.CacheData(key, "Html", html);

            return html;
        }

        public static Cache Cache
        {
            get
            {
                return HttpRuntime.Cache;
            }
        }
    }
}
